package chat;

import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import javax.swing.*;
import java.util.Calendar;

class Server implements KeyListener, ObjectStreamListener {

    int port;
    String ip;
    ServerSocket serverSocket;
    String inMessage;
    ChatWindow window;
    String nickName;
    Calendar cal;
    String time;
    int clientNumber = 0;
    ArrayList<ObjectOutputStream> clientOutputStreams = new ArrayList();
    ArrayList<ObjectStreamManager> clientManagers = new ArrayList();
    ArrayList<Socket> clientSockets = new ArrayList();

    Server() {
        try {
            startWindow();
            startServer();

        } catch (IOException e) {

            System.err.println("Couldn't start server: " + e.getMessage());
        }

        try {
            getConnections();
        } catch (IOException e) {
            System.err.println(e.getMessage());
        } finally {
            close();
        }
    }

    void close() {
        try {
            if (serverSocket != null) {
                serverSocket.close();
            }
            for (int k = 0; k < clientSockets.size(); k++) {
                if (clientSockets.get(k) != null) {
                    clientSockets.get(k).close();
                }
            }
            for (int k = 0; k < clientManagers.size(); k++) {
                if (clientManagers.get(k) != null) {
                    clientManagers.get(k).closeManager();
                }
            }
            for (int k = 0; k < clientOutputStreams.size(); k++) {
                if (clientOutputStreams.get(k) != null) {
                    clientOutputStreams.get(k).close();

                }
            }
        } catch (IOException e) {
            System.err.println("Error in closing");
        }
    }

    void startWindow() throws IOException {
        nickName = JOptionPane.showInputDialog("Choose a nickname", null);
        window = new ChatWindow("(Server) " + nickName);
        JFrame chatFrame = new JFrame(window.windowLabel);
        chatFrame.getContentPane().add(window);
        chatFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        chatFrame.pack();
        chatFrame.setVisible(true);
        window.writearea.addKeyListener(this);
        closeListener listener = new closeListener();
        window.closeButton.addActionListener(listener);
        saveTextListener tlistener = new saveTextListener();
        window.saveButton.addActionListener(tlistener);
    }

    void startServer() throws IOException {
        System.out.println("My IP: " + InetAddress.getLocalHost().getHostAddress());
        String portString = JOptionPane.showInputDialog("Through which port?", null);
        port = Integer.parseInt(portString);
        serverSocket = new ServerSocket(port);

    }

    void getConnections() throws IOException {

        while (serverSocket != null) {
            Socket socket = serverSocket.accept();
            ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
            ObjectStreamManager manager = new ObjectStreamManager(clientNumber, input, this);
            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
            clientNumber++;
            clientManagers.add(manager);
            clientOutputStreams.add(output);
            clientSockets.add(socket);
        }
    }

    void sendServerMessage() throws IOException {
        cal = Calendar.getInstance();
        time = (cal.get(cal.HOUR_OF_DAY) + ":" + cal.get(cal.MINUTE));
        if (!window.writearea.getText().equals("")) {
            for (int k = 0; k < clientOutputStreams.size(); k++) {
                clientOutputStreams.get(k).writeObject("(" + time + ")" + nickName + ": " + window.writearea.getText());
                clientOutputStreams.get(k).flush();
            }
        }
    }

    void printMessage() {
        cal = Calendar.getInstance();
        time = (cal.get(cal.HOUR_OF_DAY) + ":" + cal.get(cal.MINUTE));
        window.readarea.append("(" + time + ")" + nickName + ": " + window.writearea.getText());
        window.writearea.setText("");
    }

    public void keyTyped(KeyEvent event) {
        if (event.getKeyChar() == event.VK_ENTER) {
            try {
                sendServerMessage();
            } catch (IOException e) {
                System.err.println(e.getMessage());
            }
            printMessage();
        }
    }
    public void keyPressed(KeyEvent event) {}
    public void keyReleased(KeyEvent event) {}

    public void objectReceived(int number, Object object, Exception exception) {

        if (exception == null) {
            inMessage = (String) object;
            if (!inMessage.equals("")) {
                window.readarea.append(inMessage);
                try {
                    checkConnections();
                    for (int k = 0; k < clientOutputStreams.size(); k++) {
                        clientOutputStreams.get(k).writeObject(inMessage);
                    }
                } catch (IOException ex) {
                    System.err.println("Error in sending: " + ex.getMessage());
                }
            }
        }
    }

    void checkConnections() {
        for (int i= 0; i < clientSockets.size(); i++) {
            if (clientSockets.get(i).isClosed()) {
                clientSockets.remove(i);
                clientOutputStreams.remove(i);
                clientManagers.remove(i);
            }
        }
    }

    class closeListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            try {
                for (int k = 0; k < clientOutputStreams.size(); k++) {
                    clientOutputStreams.get(k).writeObject("The host has disconnected"+"\n");
                    clientOutputStreams.get(k).flush();
                }
            } catch (IOException f) {
                System.err.println(f.getMessage());
            }
            close();
            System.exit(0);
        }
    }

    class saveTextListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {

            JFileChooser chooser = new JFileChooser();
            int answer = chooser.showSaveDialog(null);
            if (answer == chooser.APPROVE_OPTION) {
                File savefile = chooser.getSelectedFile();
                saveDialog(savefile);
            }
        }

        void saveDialog(File file) {
            try {
                FileWriter fstream = new FileWriter(file);
                BufferedWriter out = new BufferedWriter(fstream);
                out.write(window.readarea.getText());
                out.close();
            } catch (Exception f) {
                System.err.println("Error: " + f.getMessage());
            }
        }
    }
}
